using System;
using System.Collections.Generic;

namespace Samurai.Wakizashi.Workflow
{
    public interface ISequentialWorkflow<T> : IWorkflow<T> where T : class, IWorkflowContext
    {
        /// <summary>
        /// Gets the steps that make up the current workflow instance.
        /// </summary>
        /// <value>The workflow steps.</value>
        IEnumerable<IWorkflowStep<T>> WorkflowSteps { get; }

        /// <summary>
        /// Suspends the current workflow for the specified amount of time. Once this time 
        /// has elapsed, the workflow will continue to the next step.
        /// </summary>
        /// <param name="amountOfTimeToSuspend">The amount of time to suspend.</param>
        void Suspend(TimeSpan amountOfTimeToSuspend);

        /// <summary>
        /// Configures the specified config action.
        /// </summary>
        /// <param name="configAction">The config action.</param>
        void Configure(Action<ISequentialWorkflow<T>> configAction);

        /// <summary>
        /// Registers the provided step with the workflow.
        /// </summary>
        /// <param name="step">The step.</param>
        void RegisterStep(IWorkflowStep<T> step);

        /// <summary>
        /// Registers the provided step with the workflow. Will execute if provided predicate evaluates to true at execution time. Will
        /// execute on the current thread.
        /// </summary>
        /// <param name="step">The step.</param>
        /// <param name="canExecute">Execution condition.</param>
        void RegisterStep(IWorkflowStep<T> step, Predicate<T> canExecute);

        /// <summary>
        /// Registers the provided step with the workflow on the specified thread in which to execute.
        /// </summary>
        /// <param name="step">The step.</param>
        /// <param name="thread">The thread.</param>
        void RegisterStep(IWorkflowStep<T> step, ThreadType thread);

        /// <summary>
        /// Registers the provided step with the workflow on the specified thread in which to execute. Will 
        /// execute if provided predicate evaluates to true at execution time.
        /// </summary>
        /// <param name="step">The step.</param>
        /// <param name="thread">The thread.</param>
        /// <param name="canExecute">Execution condition.</param>
        void RegisterStep(IWorkflowStep<T> step, ThreadType thread, Predicate<T> canExecute);

        /// <summary>
        /// Registers the provided action as a step in the workflow to be executed on the current thread.
        /// </summary>
        /// <param name="step">The step.</param>
        void RegisterStep(Action step);

        /// <summary>
        /// Registers the provided action as a step in the workflow on the specified thread in which to execute.
        /// </summary>
        /// <param name="step">The step.</param>
        /// <param name="thread">The thread.</param>
        void RegisterStep(Action step, ThreadType thread);

        /// <summary>
        /// Registers the provided action as a step in the workflow on the specified thread in which to execute. Will 
        /// only execute the step if execution condition evaluates to 'true' when the step is next in the workflow.
        /// </summary>
        /// <param name="step">The step.</param>
        /// <param name="canExecute">Execution condition.</param>
        void RegisterStep(Action step, Predicate<T> canExecute);

        /// <summary>
        /// Registers the provided action as a step in the workflow on the specified thread in which to execute. Will
        /// only execute the step if execution condition evaluates to 'true' when the step is next in the workflow.
        /// </summary>
        /// <param name="step">The step.</param>
        /// <param name="thread">The thread.</param>
        /// <param name="canExecute">Execution condition.</param>
        /// <param name="stepName">Name of the step.</param>
        void RegisterStep(Action step, ThreadType thread, Predicate<T> canExecute, string stepName);

        /// <summary>
        /// Registers the provided action as a step in the workflow to be executed on the current thread.
        /// </summary>
        /// <param name="step">The step.</param>
        void RegisterStep(Action<T> step);

        /// <summary>
        /// Registers the provided action as a step in the workflow on the specified thread in which to execute.
        /// </summary>
        /// <param name="step">The step.</param>
        /// <param name="thread">The thread.</param>
        void RegisterStep(Action<T> step, ThreadType thread);

        /// <summary>
        /// Registers the provided action as a step in the workflow on the specified thread in which to execute. Will 
        /// only execute the step if execution condition evaluates to 'true' when the step is next in the workflow.
        /// </summary>
        /// <param name="step">The step.</param>
        /// <param name="canExecute">Execution condition.</param>
        void RegisterStep(Action<T> step, Predicate<T> canExecute);

        /// <summary>
        /// Registers the provided action as a step in the workflow on the specified thread in which to execute. Will
        /// only execute the step if execution condition evaluates to 'true' when the step is next in the workflow.
        /// </summary>
        /// <param name="step">The step.</param>
        /// <param name="thread">The thread.</param>
        /// <param name="canExecute">Execution condition.</param>
        /// <param name="stepName">Name of the step.</param>
        void RegisterStep(Action<T> step, ThreadType thread, Predicate<T> canExecute, string stepName);
    }
}